define(function(require, exports, module) {
    "use strict";
    var $ = require("$");

    +function($) {
        "use strict";

        var PageProxy = function(options, page) {
            this.isCurrent = function() {
                return page == options.currentPage;
            }

            this.isFirst = function() {
                return page == 1;
            }

            this.isLast = function() {
                return page == options.totalPages;
            }

            this.isPrev = function() {
                return page == (options.currentPage - 1);
            }

            this.isNext = function() {
                return page == (options.currentPage + 1);
            }

            this.isLeftOuter = function() {
                return page <= options.outerWindow;
            }

            this.isRightOuter = function() {
                return (options.totalPages - page) < options.outerWindow;
            }

            this.isInsideWindow = function() {
                if (options.currentPage < options.innerWindow + 1) {
                    return page <= ((options.innerWindow * 2) + 1);
                } else if (options.currentPage > (options.totalPages - options.innerWindow)) {
                    return (options.totalPages - page) <= (options.innerWindow * 2);
                } else {
                    return Math.abs(options.currentPage - page) <= options.innerWindow;
                }
            }

            this.number = function() {
                return page;
            }
        }

        var View = {
            firstPage: function(Paginator, options, currentPageProxy) {
                var li = $('<li>').append(
                    $('<a href="#">')
                    .html(options.first)
                    .bind('click.bs-Paginator', function() {
                        Paginator.firstPage();
                        return false;
                    }));

                if (currentPageProxy.isFirst()) {
                    li.addClass("disabled");
                }

                return li;
            },

            prevPage: function(Paginator, options, currentPageProxy) {
                var li = $('<li>').append(
                    $('<a href="#">')
                    .attr("rel", "prev")
                    .html(options.prev)
                    .bind('click.bs-Paginator', function() {
                        Paginator.prevPage();
                        return false;
                    }));

                if (currentPageProxy.isFirst()) {
                    li.addClass("disabled");
                }

                return li;
            },

            nextPage: function(Paginator, options, currentPageProxy) {
                var li = $('<li>').append(
                    $('<a href="#">')
                    .attr("rel", "next")
                    .html(options.next)
                    .bind('click.bs-Paginator', function() {
                        Paginator.nextPage();
                        return false;
                    }));

                if (currentPageProxy.isLast()) {
                    li.addClass("disabled");
                }

                return li;
            },

            lastPage: function(Paginator, options, currentPageProxy) {
                var li = $('<li>').append(
                    $('<a href="#">')
                    .html(options.last)
                    .bind('click.bs-Paginator', function() {
                        Paginator.lastPage();
                        return false;
                    }));

                if (currentPageProxy.isLast()) {
                    li.addClass("disabled");
                }

                return li;
            },

            gap: function(Paginator, options) {
                return $('<li>').addClass("disabled")
                    .append($('<a href="#">').html(options.gap));
            },

            page: function(Paginator, options, pageProxy) {
                var li = $('<li>').append(function() {
                    var link = $('<a href="#">');
                    if (pageProxy.isNext()) {
                        link.attr("rel", "next")
                    }
                    if (pageProxy.isPrev()) {
                        link.attr("rel", "prev")
                    }
                    link.html(pageProxy.number());
                    link.bind('click.bs-Paginator', function() {
                        Paginator.page(pageProxy.number());
                        return false;
                    });
                    return link;
                });

                if (pageProxy.isCurrent()) {
                    li.addClass("active");
                }

                return li;
            }
        }

        // Paginator PUBLIC CLASS DEFINITION
        // ===============================

        var Paginator = function(element, options) {
            this.$element = $(element);
            this.options = $.extend({}, Paginator.DEFAULTS, options);

            this.$ul = $(element);

            this.render();
        }

        Paginator.DEFAULTS = {
            currentPage: null,
            totalPages: null,
            innerWindow: 2,
            outerWindow: 0,
            first: '<i class="fa fa-angle-double-left" title="第一页"></i>',
            prev: '<i class="fa fa-angle-left" title="上一页"></i>',
            next: '<i class="fa fa-angle-right" title="下一页"></i>',
            last: '<i class="fa fa-angle-double-right" title="最后页"></i>',
            gap: '..',
            truncate: false,
            page: function(page) {
                return true
            }
        }

        Paginator.prototype.render = function() {
            var options = this.options;

            if (!options.totalPages) {
                this.$element.hide();
                return;
            } else {
                this.$element.show();
            }

            var currentPageProxy = new PageProxy(options, options.currentPage);

            if (!currentPageProxy.isFirst() || !options.truncate) {
                if (options.first) {
                    this.$ul.append(View.firstPage(this, options, currentPageProxy));
                }

                if (options.prev) {
                    this.$ul.append(View.prevPage(this, options, currentPageProxy));
                }
            }

            var wasTruncated = false;
            for (var i = 1, length = options.totalPages; i <= length; i++) {
                var pageProxy = new PageProxy(options, i);
                if (pageProxy.isLeftOuter() || pageProxy.isRightOuter() || pageProxy.isInsideWindow()) {
                    this.$ul.append(View.page(this, options, pageProxy));
                    wasTruncated = false;
                } else {
                    if (!wasTruncated && options.outerWindow > 0) {
                        this.$ul.append(View.gap(this, options));
                        wasTruncated = true;
                    }
                }
            }

            if (!currentPageProxy.isLast() || !options.truncate) {
                if (options.next) {
                    this.$ul.append(View.nextPage(this, options, currentPageProxy));
                }

                if (options.last) {
                    this.$ul.append(View.lastPage(this, options, currentPageProxy));
                }
            }
        }

        Paginator.prototype.page = function(page, totalPages) {
            var options = this.options;

            if (totalPages === undefined) {
                totalPages = options.totalPages;
            }

            if (page > 0 && page <= totalPages) {
                if (options.page(page)) {
                    this.$ul.empty();
                    options.currentPage = page;
                    options.totalPages = totalPages;
                    this.render();
                }
            }

            return false;
        }

        Paginator.prototype.firstPage = function() {
            return this.page(1);
        }

        Paginator.prototype.lastPage = function() {
            return this.page(this.options.totalPages);
        }

        Paginator.prototype.nextPage = function() {
            return this.page(this.options.currentPage + 1);
        }

        Paginator.prototype.prevPage = function() {
            return this.page(this.options.currentPage - 1);
        }

        // Paginator PLUGIN DEFINITION
        // =========================

        var old = $.fn.Paginator;

        $.fn.Paginator = function(option) {
            var args = arguments;

            return this.each(function() {
                var $this = $(this);
                var data = $this.data('bs.Paginator');
                var options = typeof option == 'object' && option;

                if (!data) $this.data('bs.Paginator', (data = new Paginator(this, options)));
                if (typeof option == 'string') {
                    data[option].apply(data, Array.prototype.slice.call(args, 1));
                }
            });
        }

        $.fn.Paginator.Constructor = Paginator;


        // Paginator NO CONFLICT
        // ===================

        $.fn.Paginator.noConflict = function() {
            $.fn.Paginator = old;
            return this;
        }

    }(jQuery);


});
